package com.school.sports.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.school.sports.entity.Schedule;
import com.school.sports.entity.User;
import com.school.sports.service.ScheduleService;
import com.school.sports.common.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 赛程管理控制器
 * 提供赛程的增删改查、状态管理等功能
 */
@Slf4j
@RestController
@RequestMapping("/api/schedules")
public class ScheduleController {

    @Autowired
    private ScheduleService scheduleService;

    /**
     * 分页查询赛程列表
     * @param currentPage 当前页码
     * @param pageSize 每页大小
     * @param projectId 项目ID
     * @param venueId 场地ID
     * @param refereeId 裁判ID
     * @param status 赛程状态
     * @param projectName 项目名称（模糊查询）
     * @param venueName 场地名称（模糊查询）
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 分页结果
     */
    @GetMapping("/page/{currentPage}/{pageSize}")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<IPage<Schedule>> getSchedulePage(
            @PathVariable("currentPage") Integer currentPage,
            @PathVariable("pageSize") Integer pageSize,
            @RequestParam(value = "projectId", required = false) Long projectId,
            @RequestParam(value = "venueId", required = false) Integer venueId,
            @RequestParam(value = "refereeId", required = false) Long refereeId,
            @RequestParam(value = "status", required = false) String status,
            @RequestParam(value = "projectName", required = false) String projectName,
            @RequestParam(value = "venueName", required = false) String venueName,
            @RequestParam(value = "startDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startDate,
            @RequestParam(value = "endDate", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endDate) {

        log.info("分页查询赛程列表，当前页码：{}，每页条数：{}，查询条件：projectId={}, venueId={}, refereeId={}, status={}, projectName={}, venueName={}, startDate={}, endDate={}",
                currentPage, pageSize, projectId, venueId, refereeId, status, projectName, venueName, startDate, endDate);

        try {
            Page<Schedule> page = new Page<>(currentPage, pageSize);
            LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();

            // 构建查询条件
            queryWrapper.eq(projectId != null, Schedule::getProjectId, projectId)
                    .eq(venueId != null, Schedule::getVenueId, venueId)
                    .eq(refereeId != null, Schedule::getRefereeId, refereeId)
                    .eq(StringUtils.hasText(status), Schedule::getStatus, status)
                    .ge(startDate != null, Schedule::getStartTime, startDate)
                    .le(endDate != null, Schedule::getStartTime, endDate)
                    .orderByAsc(Schedule::getStartTime);

            IPage<Schedule> schedulePage = scheduleService.page(page, queryWrapper);
            log.info("查询赛程列表成功，共{}条记录", schedulePage.getTotal());
            return Result.success(schedulePage);
        } catch (Exception e) {
            log.error("查询赛程列表异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据ID查询赛程详情
     * @param scheduleId 赛程ID
     * @return 赛程详情
     */
    @GetMapping("/{scheduleId}")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<Schedule> getScheduleById(@PathVariable("scheduleId") Long scheduleId) {
        log.info("查询赛程详情，赛程ID：{}", scheduleId);

        if (scheduleId == null || scheduleId <= 0) {
            return Result.fail("赛程ID无效");
        }

        try {
            Schedule schedule = scheduleService.getScheduleWithDetails(scheduleId);
            if (schedule == null) {
                return Result.fail("赛程不存在");
            }
            log.info("查询赛程详情成功，赛程ID：{}", scheduleId);
            return Result.success(schedule);
        } catch (Exception e) {
            log.error("查询赛程详情异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 创建赛程
     * @param schedule 赛程信息
     * @return 操作结果
     */
    @PostMapping
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> createSchedule(@Valid @RequestBody Schedule schedule) {
        log.info("创建赛程：项目ID={}，场地ID={}，开始时间={}",
                schedule.getProjectId(), schedule.getVenueId(), schedule.getStartTime());

        try {
            boolean success = scheduleService.createSchedule(schedule);
            if (success) {
                log.info("创建赛程成功");
                return Result.success("创建成功");
            } else {
                return Result.fail("创建失败，请检查时间冲突或其他约束");
            }
        } catch (Exception e) {
            log.error("创建赛程异常：{}", e.getMessage(), e);
            return Result.fail("创建失败：" + e.getMessage());
        }
    }

    /**
     * 更新赛程信息
     * @param schedule 赛程信息
     * @return 操作结果
     */
    @PutMapping
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> updateSchedule(@Valid @RequestBody Schedule schedule) {
        log.info("更新赛程信息：ID={}", schedule.getId());

        try {
            boolean success = scheduleService.updateSchedule(schedule);
            if (success) {
                log.info("更新赛程成功");
                return Result.success("更新成功");
            } else {
                return Result.fail("更新失败，请检查时间冲突或其他约束");
            }
        } catch (Exception e) {
            log.error("更新赛程异常：{}", e.getMessage(), e);
            return Result.fail("更新失败：" + e.getMessage());
        }
    }

    /**
     * 删除赛程
     * @param scheduleId 赛程ID
     * @return 操作结果
     */
    @DeleteMapping("/{scheduleId}")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> deleteSchedule(@PathVariable("scheduleId") Long scheduleId) {
        log.info("删除赛程，ID：{}", scheduleId);

        if (scheduleId == null || scheduleId <= 0) {
            return Result.fail("赛程ID无效");
        }

        try {
            boolean success = scheduleService.deleteSchedule(scheduleId);
            if (success) {
                log.info("删除赛程成功");
                return Result.success("删除成功");
            } else {
                return Result.fail("删除失败，赛程可能已开始或已结束");
            }
        } catch (Exception e) {
            log.error("删除赛程异常：{}", e.getMessage(), e);
            return Result.fail("删除失败：" + e.getMessage());
        }
    }

    /**
     * 开始比赛
     * @param scheduleId 赛程ID
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/start")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判')")
    public Result<String> startSchedule(@PathVariable("scheduleId") Long scheduleId) {
        log.info("开始比赛，赛程ID：{}", scheduleId);

        try {
            boolean success = scheduleService.startSchedule(scheduleId);
            if (success) {
                log.info("开始比赛成功");
                return Result.success("比赛已开始");
            } else {
                return Result.fail("开始比赛失败，请检查赛程状态");
            }
        } catch (Exception e) {
            log.error("开始比赛异常：{}", e.getMessage(), e);
            return Result.fail("开始比赛失败：" + e.getMessage());
        }
    }

    /**
     * 结束比赛
     * @param scheduleId 赛程ID
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/end")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判')")
    public Result<String> endSchedule(@PathVariable("scheduleId") Long scheduleId) {
        log.info("结束比赛，赛程ID：{}", scheduleId);

        try {
            boolean success = scheduleService.endSchedule(scheduleId);
            if (success) {
                log.info("结束比赛成功");
                return Result.success("比赛已结束");
            } else {
                return Result.fail("结束比赛失败，请检查赛程状态");
            }
        } catch (Exception e) {
            log.error("结束比赛异常：{}", e.getMessage(), e);
            return Result.fail("结束比赛失败：" + e.getMessage());
        }
    }

    /**
     * 延期比赛
     * @param scheduleId 赛程ID
     * @param newStartTime 新开始时间
     * @param newEndTime 新结束时间
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/postpone")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> postponeSchedule(
            @PathVariable("scheduleId") Long scheduleId,
            @RequestParam("newStartTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime newStartTime,
            @RequestParam("newEndTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime newEndTime) {

        log.info("延期比赛，赛程ID：{}，新时间：{} - {}", scheduleId, newStartTime, newEndTime);

        try {
            boolean success = scheduleService.postponeSchedule(scheduleId, newStartTime, newEndTime);
            if (success) {
                log.info("延期比赛成功");
                return Result.success("比赛已延期");
            } else {
                return Result.fail("延期失败，请检查时间冲突或其他约束");
            }
        } catch (Exception e) {
            log.error("延期比赛异常：{}", e.getMessage(), e);
            return Result.fail("延期失败：" + e.getMessage());
        }
    }

    /**
     * 取消比赛
     * @param scheduleId 赛程ID
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/cancel")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> cancelSchedule(@PathVariable("scheduleId") Long scheduleId) {
        log.info("取消比赛，赛程ID：{}", scheduleId);

        try {
            boolean success = scheduleService.cancelSchedule(scheduleId);
            if (success) {
                log.info("取消比赛成功");
                return Result.success("比赛已取消");
            } else {
                return Result.fail("取消失败，请检查赛程状态");
            }
        } catch (Exception e) {
            log.error("取消比赛异常：{}", e.getMessage(), e);
            return Result.fail("取消失败：" + e.getMessage());
        }
    }

    /**
     * 分配裁判
     * @param scheduleId 赛程ID
     * @param refereeId 裁判ID
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/assign-referee")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> assignReferee(
            @PathVariable("scheduleId") Long scheduleId,
            @RequestParam("refereeId") Long refereeId) {

        log.info("分配裁判，赛程ID：{}，裁判ID：{}", scheduleId, refereeId);

        try {
            boolean success = scheduleService.assignReferee(scheduleId, refereeId);
            if (success) {
                log.info("分配裁判成功");
                return Result.success("裁判分配成功");
            } else {
                return Result.fail("分配失败，裁判时间冲突");
            }
        } catch (Exception e) {
            log.error("分配裁判异常：{}", e.getMessage(), e);
            return Result.fail("分配失败：" + e.getMessage());
        }
    }

    /**
     * 更换裁判
     * @param scheduleId 赛程ID
     * @param newRefereeId 新裁判ID
     * @return 操作结果
     */
    @PutMapping("/{scheduleId}/change-referee")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<String> changeReferee(
            @PathVariable("scheduleId") Long scheduleId,
            @RequestParam("newRefereeId") Long newRefereeId) {

        log.info("更换裁判，赛程ID：{}，新裁判ID：{}", scheduleId, newRefereeId);

        try {
            boolean success = scheduleService.changeReferee(scheduleId, newRefereeId);
            if (success) {
                log.info("更换裁判成功");
                return Result.success("裁判更换成功");
            } else {
                return Result.fail("更换失败，新裁判时间冲突");
            }
        } catch (Exception e) {
            log.error("更换裁判异常：{}", e.getMessage(), e);
            return Result.fail("更换失败：" + e.getMessage());
        }
    }

    /**
     * 根据项目ID查询赛程列表
     * @param projectId 项目ID
     * @return 赛程列表
     */
    @GetMapping("/project/{projectId}")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getSchedulesByProjectId(@PathVariable("projectId") Long projectId) {
        log.info("根据项目ID查询赛程列表，项目ID：{}", projectId);

        try {
            List<Schedule> schedules = scheduleService.getSchedulesByProjectId(projectId);
            log.info("查询赛程列表成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("查询赛程列表异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据场地ID查询赛程列表
     * @param venueId 场地ID
     * @return 赛程列表
     */
    @GetMapping("/venue/{venueId}")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getSchedulesByVenueId(@PathVariable("venueId") Integer venueId) {
        log.info("根据场地ID查询赛程列表，场地ID：{}", venueId);

        try {
            List<Schedule> schedules = scheduleService.getSchedulesByVenueId(venueId);
            log.info("查询赛程列表成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("查询赛程列表异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取今日赛程
     * @return 今日赛程列表
     */
    @GetMapping("/today")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getTodaySchedules() {
        log.info("获取今日赛程");

        try {
            List<Schedule> schedules = scheduleService.getTodaySchedules();
            log.info("获取今日赛程成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("获取今日赛程异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 获取本周赛程
     * @return 本周赛程列表
     */
    @GetMapping("/week")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getWeekSchedules() {
        log.info("获取本周赛程");

        try {
            List<Schedule> schedules = scheduleService.getWeekSchedules();
            log.info("获取本周赛程成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("获取本周赛程异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 获取即将开始的赛程
     * @return 即将开始的赛程列表
     */
    @GetMapping("/upcoming")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getUpcomingSchedules() {
        log.info("获取即将开始的赛程");

        try {
            List<Schedule> schedules = scheduleService.getUpcomingSchedules();
            log.info("获取即将开始的赛程成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("获取即将开始的赛程异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 获取赛程状态统计
     * @return 统计结果
     */
    @GetMapping("/statistics")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<Map<String, Long>> getScheduleStatistics() {
        log.info("获取赛程状态统计");

        try {
            Map<String, Long> statistics = scheduleService.getScheduleStatusStatistics();
            log.info("获取赛程状态统计成功");
            return Result.success(statistics);
        } catch (Exception e) {
            log.error("获取赛程状态统计异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 获取赛程状态列表
     * @return 赛程状态列表
     */
    @GetMapping("/statuses")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<String>> getScheduleStatuses() {
        log.info("获取赛程状态列表");

        try {
            List<String> statuses = scheduleService.getAllScheduleStatuses();
            log.info("获取赛程状态列表成功，共{}种状态", statuses.size());
            return Result.success(statuses);
        } catch (Exception e) {
            log.error("获取赛程状态列表异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 检查场地可用性
     * @param venueId 场地ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 检查结果
     */
    @GetMapping("/check-venue")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<Boolean> checkVenueAvailability(
            @RequestParam("venueId") Integer venueId,
            @RequestParam("startTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam("endTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        log.info("检查场地可用性，场地ID：{}，时间：{} - {}", venueId, startTime, endTime);

        try {
            boolean isAvailable = scheduleService.isVenueAvailable(venueId, startTime, endTime);
            return Result.success(isAvailable);
        } catch (Exception e) {
            log.error("检查场地可用性异常：{}", e.getMessage(), e);
            return Result.fail("检查失败：" + e.getMessage());
        }
    }

    /**
     * 检查裁判可用性
     * @param refereeId 裁判ID
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 检查结果
     */
    @GetMapping("/check-referee")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<Boolean> checkRefereeAvailability(
            @RequestParam("refereeId") Long refereeId,
            @RequestParam("startTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam("endTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        log.info("检查裁判可用性，裁判ID：{}，时间：{} - {}", refereeId, startTime, endTime);

        try {
            boolean isAvailable = scheduleService.isRefereeAvailable(refereeId, startTime, endTime);
            return Result.success(isAvailable);
        } catch (Exception e) {
            log.error("检查裁判可用性异常：{}", e.getMessage(), e);
            return Result.fail("检查失败：" + e.getMessage());
        }
    }

    /**
     * 获取我的赛程（裁判专用）
     * @return 我的赛程列表
     */
    @GetMapping("/my-schedules")
    @PreAuthorize("hasRole('裁判')")
    public Result<List<Schedule>> getMySchedules() {
        log.info("获取我的赛程");

        try {
            User currentUser = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            List<Schedule> schedules = scheduleService.getSchedulesByRefereeId(currentUser.getId());
            log.info("获取我的赛程成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("获取我的赛程异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 根据日期范围查询赛程
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 赛程列表
     */
    @GetMapping("/date-range")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getSchedulesByDateRange(
            @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startDate,
            @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endDate) {

        log.info("根据日期范围查询赛程，开始时间：{}，结束时间：{}", startDate, endDate);

        try {
            List<Schedule> schedules = scheduleService.getSchedulesByDateRange(startDate, endDate);
            log.info("查询赛程列表成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("查询赛程列表异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取赛程日历数据
     * @param year 年份
     * @param month 月份
     * @return 日历数据
     */
    @GetMapping("/calendar")
    @PreAuthorize("hasAnyRole('管理员', '老师', '裁判', '学生')")
    public Result<List<Schedule>> getScheduleCalendarData(
            @RequestParam("year") Integer year,
            @RequestParam("month") Integer month) {

        log.info("获取赛程日历数据，年份：{}，月份：{}", year, month);

        try {
            LocalDateTime startDate = LocalDateTime.of(year, month, 1, 0, 0);
            LocalDateTime endDate = startDate.plusMonths(1).minusSeconds(1);

            List<Schedule> schedules = scheduleService.getSchedulesByDateRange(startDate, endDate);
            log.info("获取赛程日历数据成功，共{}条记录", schedules.size());
            return Result.success(schedules);
        } catch (Exception e) {
            log.error("获取赛程日历数据异常：{}", e.getMessage(), e);
            return Result.fail("获取失败：" + e.getMessage());
        }
    }

    /**
     * 校验状态合法性
     */
    private boolean isValidStatus(String status) {
        return Arrays.asList("未开始", "进行中", "已结束", "延期", "取消").contains(status);
    }
}